package org.gluedom.data;

import static com.google.common.base.Preconditions.checkNotNull;

import java.util.Collection;
import java.util.List;

import com.google.common.collect.ImmutableList;

public class Attribute implements Immutable, Identifiable, PropertyContainer {
	private final Identifier identifier;
	private final String type;
	private final List<Property> properties;

	private volatile int hash = 0;

	private Attribute(Builder builder) {
		identifier = builder.identifier.identifier;
		type = builder.type;
		properties = ImmutableList.copyOf(builder.properties.properties);
	}

	@Override
	public Identifier getIdentifier() {
		return identifier;
	}

	public String getType() {
		return type;
	}

	@Override
	public Iterable<Property> getProperties() {
		return properties;
	}

	@Override
	public String getProperty(String name) {
		return Property.findProperty(name, properties);
	}

	public static final class Builder {
		private final Identifiable.Builder identifier;
		private String type;
		private final PropertyContainer.Builder properties = new PropertyContainer.Builder();

		public Builder(Attribute attribute) {
			identifier = new Identifiable.Builder(attribute.identifier);
			type = attribute.type;
			properties.properties(attribute.properties);
		}

		public Builder(Identifier identifier, String type) {
			this.identifier = new Identifiable.Builder(checkNotNull(identifier));
			this.type = checkNotNull(type);
		}

		public Builder identifier(Identifier identifier) {
			this.identifier.identifier(checkNotNull(identifier));
			return this;
		}

		public Builder type(String type) {
			this.type = checkNotNull(type);
			return this;
		}

		public Builder property(String name, String value) {
			properties.property(name, value);
			return this;
		}

		public Builder property(Property property) {
			properties.property(checkNotNull(property));
			return this;
		}

		public Builder properties(Collection<Property> properties) {
			this.properties.properties(properties);
			return this;
		}

		public Attribute build() {
			return new Attribute(this);
		}
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		sb.append(identifier);
		sb.append(":");
		sb.append(type);
		sb.append(" ");
		sb.append(properties);
		return sb.toString();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof Attribute))
			return false;
		Attribute other = (Attribute) obj;
		if (hashCode() != other.hashCode())
			return false;
		if (!identifier.equals(other.identifier))
			return false;
		if (!type.equals(other.type))
			return false;
		if (!properties.equals(other.properties))
			return false;
		return true;
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	public int hashCode() {
		if (hash == 0) {
			int result = 4839;
			result = 31 * result + identifier.hashCode();
			result = 31 * result + type.hashCode();
			result = 31 * result + properties.hashCode();
			hash = result;
		}
		return hash;
	}
}
